package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tiancheng.trade.commom.core.data.PageInfo;
import com.tiancheng.trade.commom.core.data.Result;
import com.tiancheng.trade.settlement.enums.*;
import com.tiancheng.trade.settlement.exception.BusinessException;
import com.tiancheng.trade.settlement.feign.OrderService;
import com.tiancheng.trade.settlement.mapper.settlement.FlowSubOrderMapper;
import com.tiancheng.trade.settlement.mapper.settlement.PaymentBillMapper;
import com.tiancheng.trade.settlement.mapper.settlement.PaymentOrderBankDetailMapper;
import com.tiancheng.trade.settlement.mapper.settlement.PaymentOrderFinishMapper;
import com.tiancheng.trade.settlement.model.settlement.FlowSubOrder;
import com.tiancheng.trade.settlement.model.settlement.PaymentBill;
import com.tiancheng.trade.settlement.model.settlement.PaymentOrderBankDetail;
import com.tiancheng.trade.settlement.model.settlement.PaymentOrderFinish;
import com.tiancheng.trade.settlement.service.settlement.IPaymentBillQueryService;
import com.tiancheng.trade.settlement.util.ExcelUtil;
import com.tiancheng.trade.settlement.util.ObjectConvertUtil;
import com.tiancheng.trade.settlement.vo.settlement.admin.PaymentBillDetailQuery;
import com.tiancheng.trade.settlement.vo.settlement.admin.PaymentBillQueryVO;
import com.tiancheng.trade.settlement.vo.settlement.admin.res.*;
import com.tiancheng.trade.settlement.vo.settlement.api.CellMergeVO;
import com.tiancheng.trade.settlement.vo.settlement.export.PaymentBillListExportVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PaymentBillQueryService implements IPaymentBillQueryService {


    @Autowired
    private PaymentOrderFinishMapper paymentOrderFinishMapper;
    @Autowired
    private PaymentBillMapper paymentBillMapper;
    @Autowired
    private PaymentOrderBankDetailMapper paymentOrderBankDetailMapper;
    @Autowired
    private OrderService orderService;
    @Autowired
    private FlowSubOrderMapper flowSubOrderMapper;

    @Override
    public PageInfo<PaymentBillSummaryResVO> querySummaryView(PaymentBillQueryVO queryVO) throws BusinessException {
        Page<PaymentBillSummaryResVO> page = new Page<>();
        page.setCurrent(queryVO.getCurrentPage());
        page.setSize(queryVO.getPageSize());

        IPage<PaymentBillSummaryResVO> pageresult = paymentOrderFinishMapper.querySummaryView(page, queryVO);
        PageInfo.Pagination pagination = new PageInfo.Pagination(queryVO.getCurrentPage(), queryVO.getPageSize(), page.getTotal());
        return new PageInfo<>(pageresult.getRecords(), pagination);
    }

    @Override
    public PageInfo<PaymentBillListResVO> queryItemList(PaymentBillDetailQuery queryVO) throws BusinessException {
        if (StringUtils.isNotBlank(queryVO.getReconciliationStatus())) {
            if (StringUtils.equals("un_success", queryVO.getReconciliationStatus())) {//查询异常数据
                List<String> list = new ArrayList<String>();
                list.add(PaymentBillStatusEnum.ABNORMAL.getCode());
                list.add(PaymentBillStatusEnum.NO_MATCH.getCode());
                queryVO.setReconciliationStatusList(list);
                queryVO.setReconciliationStatus("");
            }
            if (StringUtils.equals("success", queryVO.getReconciliationStatus())) {//查询异常数据
                List<String> list = new ArrayList<String>();
                list.add(PaymentBillStatusEnum.SUCCESS.getCode());
                list.add(PaymentBillStatusEnum.UP_SUCCESS.getCode());
                queryVO.setReconciliationStatusList(list);
                queryVO.setReconciliationStatus("");
            }

        }
        Page<PaymentBillListResVO> page = new Page<>();
        page.setCurrent(queryVO.getCurrentPage());
        page.setSize(queryVO.getPageSize());
        IPage<PaymentBillListResVO> pageresult = paymentOrderFinishMapper.queryPaymentBillFinish(page, queryVO);
        PageInfo.Pagination pagination = new PageInfo.Pagination(queryVO.getCurrentPage(), queryVO.getPageSize(), page.getTotal());
        List<PaymentBillListResVO> list = pageresult.getRecords();

        List<String> flows = list.stream().map(PaymentBillListResVO::getFlowId).collect(Collectors.toList());
        List<FlowSubOrder> flowSubOrderList = new ArrayList<FlowSubOrder>();
        if (CollectionUtils.isNotEmpty(flows)) {
            List<String> flowsStr = flows.stream().distinct().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(flowsStr)) {
                QueryWrapper<FlowSubOrder> conditions = new QueryWrapper<>();
                conditions.in("flow_id", flowsStr);
                conditions.isNotNull("error_reason");
                flowSubOrderList = flowSubOrderMapper.selectList(conditions);
            }
        }

        for (PaymentBillListResVO item : list) {
            item.setTransactionTypeCn(TransactionTypeEnum.getDesc(item.getTransactionType()));
            if (item.getBankPayAmount() == null) {
                item.setBankPayAmount(0);
            }
            if (item.getOrderAmount() == null) {
                item.setOrderAmount(0);
            }
            item.setDiffAmount(item.getOrderAmount() - Math.abs(item.getBankPayAmount()));
            if (TransactionTypeEnum.REFUND.getCode().equals(item.getTransactionType())) {
                item.setPayTime(item.getRefundTime());
            }
            if (CollectionUtils.isNotEmpty(flowSubOrderList)) {
                List<FlowSubOrder> flowList = flowSubOrderList.stream().filter(x -> StringUtils.isNotEmpty(x.getFlowId()) && x.getFlowId().equals(item.getFlowId())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(flowList)) {
                    List<String> reasonList = new ArrayList<String>();
                    flowList.forEach(a -> {
                        if (StringUtils.isNotEmpty(a.getErrorReason())) {
                            if (StringUtils.isNotEmpty(ErrorReasonEnum.getDesc(a.getErrorReason()))) {
                                reasonList.add(ErrorReasonEnum.getDesc(a.getErrorReason()));
                            } else {
                                reasonList.add(a.getErrorReason());
                            }
                        }
                    });
                    item.setRemark(StringUtils.join(reasonList, ","));
                }
            }
        }
        return new PageInfo<>(list, pagination);
    }

    @Override
    public PaymentBillDetailResVO queryItemDetail(Long id) throws BusinessException {

        Assert.notNull(id, "参数错误");
        PaymentOrderFinish data = paymentOrderFinishMapper.selectById(id);
        Assert.notNull(data, "未查到该记录");
        PaymentBillDetailResVO res = new PaymentBillDetailResVO();

        if (data != null) {
            //对帐信息
            BeanUtils.copyProperties(data, res);
            //差异金额
            Integer payAmount = data.getPayAmount() == null ? 0 : data.getPayAmount();
            Integer bankPayAmount = data.getBankPayAmount() == null ? 0 : Math.abs(data.getBankPayAmount());
            res.setErrorAmount(payAmount - bankPayAmount);
        }
        //订单信息
        Result<List<OrderResVO>> orderRes = orderService.fetchQueryOrderByFlowId(data.getFlowId());

        //支付订单详情
        QueryWrapper<PaymentBill> paymentBillconditions = new QueryWrapper<>();
        paymentBillconditions.eq("pay_channel_orderid", data.getPayChannelOrderid());
        paymentBillconditions.eq("transaction_type", data.getTransactionType());
        PaymentBill paymentBill = paymentBillMapper.selectOne(paymentBillconditions);
        if (paymentBill != null) {
            if (TransactionTypeEnum.REFUND.getCode().equals(paymentBill.getTransactionType())) {
                paymentBill.setPayTime(paymentBill.getRefundTime());
            }
            BeanUtils.copyProperties(paymentBill, res.getPaymentOrderRes());
            PaymentOrderResVO paymentOrderResVO = res.getPaymentOrderRes();
            paymentOrderResVO.setTransactionTypeCN(TransactionTypeEnum.getDesc(paymentOrderResVO.getTransactionType()));
            paymentOrderResVO.setPayChannelCN(PaymentChannelEnum.getDesc(paymentOrderResVO.getPayChannel()));
            paymentOrderResVO.setPayWayCN(PayWayEnum.getDesc(paymentOrderResVO.getPayWay()));
            if (orderRes.getRet() == 0) {
                orderRes.getData().forEach(a -> {
                    paymentOrderResVO.setOrderNum(a.getSubOrders().size());
                });
            }
            res.setPaymentOrderRes(paymentOrderResVO);
        }
        //银行帐单详情
        QueryWrapper<PaymentOrderBankDetail> paymentOrderBankConditions = new QueryWrapper<>();
        paymentOrderBankConditions.eq("pay_channel_orderid", data.getPayChannelOrderid());
        PaymentOrderBankDetail paymentOrderBank = paymentOrderBankDetailMapper.selectOne(paymentOrderBankConditions);
        if (paymentOrderBank != null) {
            BeanUtils.copyProperties(paymentOrderBank, res.getBankRes());
            PaymentOrderBankResVO bankResVO = res.getBankRes();
            bankResVO.setTransactionTypeCN(TransactionTypeEnum.getDesc(bankResVO.getTransactionType()));
            bankResVO.setPayChannelCN(PaymentChannelEnum.getDesc(bankResVO.getPayChannel()));
            bankResVO.setPayWayCN(PayWayEnum.getDesc(bankResVO.getPayWay()));
            bankResVO.setPayAmount(Math.abs(bankResVO.getPayAmount()));//负数转正数，页面统一用绝对值显示
            res.setPayAmount(Math.abs(bankResVO.getPayAmount()));
            res.setBankRes(bankResVO);
        }

        String errorHandle = "";
        LocalDateTime errorHandleTime = LocalDateTime.now();
        //子订单标记信息
        List<FlowSubOrder> flowSubOrder = new ArrayList<FlowSubOrder>();
        if (StringUtils.isNotEmpty(data.getFlowId())) {
            QueryWrapper<FlowSubOrder> conditions = new QueryWrapper<>();
            conditions.eq("flow_id", data.getFlowId());
            flowSubOrder = flowSubOrderMapper.selectList(conditions);

            if (CollectionUtils.isNotEmpty(flowSubOrder)) {
                errorHandle = flowSubOrder.get(0).getErrorHandle();
                res.setLastUpdBy(errorHandle);
                if (null != flowSubOrder.get(0).getErrorHandleTime()) {
                    errorHandleTime = flowSubOrder.get(0).getErrorHandleTime().toLocalDateTime();
                    res.setLastUpdDt(errorHandleTime);
                }
            }
            res.setFlowSubOrder(flowSubOrder);
        }

        if (orderRes.getRet() == 0) {
            res.setOrderListRes(orderRes.getData());
        }
        return res;
    }

    @Override
    public void export(PaymentBillDetailQuery queryVO, HttpServletRequest request, HttpServletResponse response) throws IOException {

        String[] title = {"交易类型", "支付订单号", "渠道支付订单号", "订单金额(元)", "优惠金额(元)", "交易金额(元)", "通道费(元)", "订单金额(元)", "优惠金额(元)", "交易金额(元)", "通道费(元)", "交易时间", "对账时间", "差异(元)", "差异原因"};
        HashMap<Integer, String> title1 = new HashMap<>();
        title1.put(0, "平台流水");
        title1.put(7, "银行流水");
        title1.put(12, "对账结果");

        if (StringUtils.isNotBlank(queryVO.getReconciliationStatus())) {
            if (StringUtils.equals("un_success", queryVO.getReconciliationStatus())) {//查询异常数据
                List<String> list = new ArrayList<String>();
                list.add(PaymentBillStatusEnum.ABNORMAL.getCode());
                list.add(PaymentBillStatusEnum.NO_MATCH.getCode());
                queryVO.setReconciliationStatusList(list);
                queryVO.setReconciliationStatus("");
            }
        }
        List<PaymentBillListResVO> list = paymentOrderFinishMapper.queryPaymentBillFinish(queryVO);
        List<String> flows = list.stream().map(PaymentBillListResVO::getFlowId).collect(Collectors.toList());
        List<FlowSubOrder> flowSubOrderList = new ArrayList<FlowSubOrder>();
        if (CollectionUtils.isNotEmpty(flows)) {
            List<String> flowsStr = flows.stream().distinct().collect(Collectors.toList());
            QueryWrapper<FlowSubOrder> conditions = new QueryWrapper<>();
            conditions.in("flow_id", flowsStr);
            flowSubOrderList = flowSubOrderMapper.selectList(conditions);
        }

        for (PaymentBillListResVO item : list) {

            item.setTransactionTypeCn(TransactionTypeEnum.getDesc(item.getTransactionType()));
            if (item.getBankPayAmount() == null) {
                item.setBankPayAmount(0);
            }
            if (item.getPayAmount() == null) {
                item.setPayAmount(0);
            }
            item.setDiffAmount(item.getPayAmount() - item.getBankPayAmount());
            if (TransactionTypeEnum.REFUND.getCode().equals(item.getTransactionType())) {
                item.setPayTime(item.getRefundTime());
            }

            if (CollectionUtils.isNotEmpty(flowSubOrderList)) {
                List<FlowSubOrder> flowList = flowSubOrderList.stream().filter(x -> StringUtils.isNotEmpty(x.getFlowId()) && x.getFlowId().equals(item.getFlowId())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(flowList)) {
                    List<String> reasonList = new ArrayList<String>();
                    flowList.forEach(a -> {
                        if (StringUtils.isNotEmpty(a.getErrorReason())) {
                            if (StringUtils.isNotEmpty(ErrorReasonEnum.getDesc(a.getErrorReason()))) {
                                reasonList.add(ErrorReasonEnum.getDesc(a.getErrorReason()));
                            } else {
                                reasonList.add(a.getErrorReason());
                            }
                        }
                    });
                    item.setRemark(StringUtils.join(reasonList, ","));
                }
            }
        }

        if (CollectionUtils.isNotEmpty(list)) {
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
            BigDecimal num1 = new BigDecimal("100");
            List<PaymentBillListExportVO> bList = list.stream().map(a -> {
                a.setTransactionType(TransactionTypeEnum.getDesc(a.getTransactionType()));

                PaymentBillListExportVO export = ObjectConvertUtil.convert(a, PaymentBillListExportVO.class).get();
                if (null != a.getOrderAmount()) {
                    BigDecimal orderAmount = new BigDecimal(a.getOrderAmount());
                    export.setOrderAmount(orderAmount.divide(num1).toString());
                }
                if (null != a.getDiscount()) {
                    BigDecimal discount = new BigDecimal(a.getDiscount());
                    export.setDiscount(discount.divide(num1).toString());
                }
                if (null != a.getPayAmount()) {
                    BigDecimal payAmount = new BigDecimal(a.getPayAmount());
                    export.setPayAmount(payAmount.divide(num1).toString());
                }
                if (null != a.getServiceCharge()) {
                    BigDecimal serviceCharge = new BigDecimal(a.getServiceCharge());
                    export.setServiceCharge(serviceCharge.divide(num1).toString());
                }
                if (null != a.getBankOrderAmount()) {
                    BigDecimal bankOrderAmount = new BigDecimal(a.getBankOrderAmount());
                    export.setBankOrderAmount(bankOrderAmount.divide(num1).toString());
                }
                if (null != a.getBankPayAmount()) {
                    BigDecimal bankPayAmount = new BigDecimal(a.getBankPayAmount());
                    export.setBankPayAmount(bankPayAmount.divide(num1).toString());
                }
                if (null != a.getBankDiscount()) {
                    BigDecimal bankDiscount = new BigDecimal(a.getBankDiscount());
                    export.setBankDiscount(bankDiscount.divide(num1).toString());
                }
                if (null != a.getBankServiceCharge()) {
                    BigDecimal bankServiceCharge = new BigDecimal(a.getBankServiceCharge());
                    export.setBankServiceCharge(bankServiceCharge.divide(num1).toString());
                }

                if (null != a.getDiffAmount()) {
                    BigDecimal diffAmount = new BigDecimal(a.getDiffAmount());
                    export.setDiffAmount(diffAmount.divide(num1).toString());
                }

                if (null != a.getPayTime()) {
                    export.setPayTime(a.getPayTime().format(sdf));
                }
                if (null != a.getReconciliationTime()) {
                    export.setReconciliationTime(a.getReconciliationTime().format(sdf));
                }

                return export;
            }).collect(Collectors.toList());

            List<Map<String, Object>> mapList = listConvert(bList);
            String fileName = "流水明细对账.xlsx";
            Workbook workbook = ExcelUtil.buildWorkbook2("流水明细对账", title1, title, mapList, getCellMergeData());
            ExcelUtil.exportExcle(request, response, workbook, fileName);
        }
    }

    /**
     * 数据转换
     *
     * @param list
     * @return
     */
    private List<Map<String, Object>> listConvert(List<PaymentBillListExportVO> list) {
        List<Map<String, Object>> list_map = new ArrayList<Map<String, Object>>();
        try {
            for (PaymentBillListExportVO t : list) {
                Field[] fields = t.getClass().getDeclaredFields();
                Map<String, Object> m = new LinkedHashMap<String, Object>();
                for (Field field : fields) {
                    String keyName = field.getName();
                    PropertyDescriptor pd = new PropertyDescriptor(keyName, t.getClass());
                    Method getMethod = pd.getReadMethod();// 获得getter方法
                    Object o = getMethod.invoke(t);// 执行get方法返回一个Object
                    m.put(keyName, o);
                }
                list_map.add(m);
            }
            return list_map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private List<CellMergeVO> getCellMergeData() {
        List<CellMergeVO> list = new ArrayList<>();
        CellMergeVO vo = new CellMergeVO();
        vo.setStartRow(0);
        vo.setStartCol(0);
        vo.setEndRow(0);
        vo.setEndCol(6);
        list.add(vo);
        vo = new CellMergeVO();
        vo.setStartRow(0);
        vo.setStartCol(7);
        vo.setEndRow(0);
        vo.setEndCol(11);
        list.add(vo);
        vo = new CellMergeVO();
        vo.setStartRow(0);
        vo.setStartCol(12);
        vo.setEndRow(0);
        vo.setEndCol(14);
        list.add(vo);
        return list;
    }

}
